﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using SocketClient.Common;

namespace SocketClient
{
    public partial class FormMain : Form
    {
        private Socket mSocket;

        private TcpClient mTcpClient;

        private UdpClient mUdpClient;

        private EndPoint mRemoteEndPoint;

        private NetworkStream mStream;

        public FormMain()
        {
            InitializeComponent();
        }

        private void buttonSend_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(textBoxMessage.Text))
            {
                return;
            }

            if (mSocket == null)
            {
                try
                {
                    mRemoteEndPoint = new IPEndPoint(IPAddress.Parse(Config.SocketServerIPAddress), Config.SocketServerPort);
                    mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    mSocket.Connect(mRemoteEndPoint);
                    if (!mSocket.Connected)
                    {
                        MessageBox.Show("Connection failure 1.", "Information");
                        return;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Init socket failure.");
                    return;
                }                
            }

            //if (!IsSocketConnected(mSocket))
            //{
            //    try
            //    {
            //        mSocket.Connect(mRemoteEndPoint);
            //    }
            //    catch
            //    {
            //        MessageBox.Show("Connection failure 2.");
            //        return;
            //    }
            //}                     

            string message = textBoxMessage.Text;
            byte[] data = Encoding.UTF8.GetBytes(message);

            //send message
            try
            {
                textBoxMessage.Text = string.Empty;

                listBoxHistory.Items.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": ");
                listBoxHistory.Items.Add(message);

                mSocket.Send(data, data.Length, SocketFlags.None);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Send message failure.");                                
            }

            //receive message
            //StringBuilder sbReceive = new StringBuilder();
            //sbReceive.Append("server " + DateTime.Now.ToString("yyyyMMdd HH:mm:ss") + ": ");

            //byte[] receiveData = new byte[1024];
            //while (mSocket.Receive(receiveData, SocketFlags.OutOfBand) > 0)
            //{
            //    sbReceive.Append(Encoding.UTF8.GetString(receiveData));
            //}

            //listBoxHistory.Items.Add(sbReceive.ToString());
        }

        /// <summary>
        /// Show whether the socket is connected at a certain moment.
        /// </summary>
        /// <param name="socket"></param>
        /// <returns>true if socket is connected, false if socket is disconnected.</returns>
        public bool IsSocketConnected(Socket socket)
        {
            bool returnValue = false;

            if (socket != null)
            {
                // Socket.Connected doesn't tell us if the socket is actually connected...
                // http://msdn2.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspx

                bool disposed = false;
                bool blocking = socket.Blocking;

                try
                {
                    socket.Blocking = false;
                    int pollWait = 1;

                    if (socket.Poll(pollWait, SelectMode.SelectRead) && socket.Available == 0)
                    {
                        returnValue = false;
                    }
                    else
                    {
                        returnValue = true;
                    }

                }
                catch (SocketException ex)
                {
                    // 10035 == WSAEWOULDBLOCK
                    if (ex.NativeErrorCode.Equals(10035))
                    {
                        returnValue = true;
                    }                        
                }
                catch (ObjectDisposedException)
                {
                    disposed = true;
                    returnValue = false;
                }
                finally
                {
                    if (!disposed)
                    {
                        socket.Blocking = blocking;
                    }
                }
            }

            return returnValue;
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            listBoxHistory.Items.Clear();
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {            
            CloseSocketClient();

            CloseTcpClient();
        }

        private void CloseTcpClient()
        {
            try
            {
                if (mTcpClient != null && mTcpClient.Connected)
                {
                    mTcpClient.Close();
                    mTcpClient = null;
                }
            }
            catch
            {
                
            }
        }

        private void CloseSocketClient()
        {
            try
            {
                if (mSocket != null)
                {                    
                    mSocket.Shutdown(SocketShutdown.Send);
                    mSocket.Close();
                    mSocket = null;
                }
            }
            catch
            {               
                
            }
        }

        private void textBoxMessage_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
            {
                buttonSend_Click(sender, e);
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
            
        }

        private void buttonSendByTcp_Click(object sender, EventArgs e)
        {
            string message = textBoxMessage.Text.Trim();
            if (string.IsNullOrEmpty(message))
            {
                return;
            }

            try
            {
                if (mTcpClient == null)
                {
                    mTcpClient = new TcpClient();
                    mTcpClient.LingerState = new LingerOption(true, 5);
                    mTcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                    mTcpClient.Connect(Config.SocketServerIPAddress, Config.SocketServerPort);
                }
                
                mStream = mTcpClient.GetStream();
                byte[] buffer = Encoding.UTF8.GetBytes(message);

                mStream.Write(buffer, 0, buffer.Length);
                mStream.Flush();

                textBoxMessage.Text = string.Empty;

                listBoxHistory.Items.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": " + message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
            }            
        }

        private void buttonSendByUdp_Click(object sender, EventArgs e)
        {
            string message = textBoxMessage.Text.Trim();
            if (string.IsNullOrEmpty(message))
            {
                return;
            }

            try
            {
                if (mUdpClient == null)
                {
                    mUdpClient = new UdpClient();
                    mUdpClient.Connect(Config.SocketServerIPAddress, Config.SocketServerPort);
                }                

                byte[] requestData = Encoding.UTF8.GetBytes(message);
                mUdpClient.Send(requestData, requestData.Length);

                IPEndPoint remoteEndPoint = null;
                byte[] receivedData = mUdpClient.Receive(ref remoteEndPoint);

                string responseData = Encoding.UTF8.GetString(receivedData);

                listBoxHistory.Items.Add("server: " + responseData);
            }
            catch
            {
                               
            }
        }
    }
}
